from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.safestring import mark_safe
from pagemagic.utils.ordering.models import OrderingModel
from django.core.urlresolvers import resolve

class Allpages(object):
    def __init__(self):
        self.by_pk = {}
        self.by_path = {}
        self.by_name = {}
        self.by_level = {}
        self.by_parent = {}

#class Page(models.Model):
class Page(OrderingModel):
    enabled = models.BooleanField(_('show in menu'), default=True)
    parent = models.ForeignKey('self', verbose_name=_('parent page'), null=True, blank=True,
        help_text=_('Leave blank for root level page'))
    path = models.CharField(_('path'), max_length=255, db_index=True,
        blank=True, null=True,
        help_text=_('Page path on site, starts and ends with "/"'))
    name = models.CharField(_('name'), max_length=255, db_index=True,
        blank=True, null=True,
        help_text=_('Name for access from code'))
    #order = models.PositiveIntegerField(_('order'), default=0, editable=False)
    level = models.PositiveIntegerField(_('level'), editable=False)

    def set_allpages_cache(self, d):
        self._allpages_cache = d

    @classmethod
    def preload(cls):
        pages = Allpages()

        #page_objects = list(cls.objects.select_related().filter(enabled=True))
        page_objects = list(cls.objects.select_related().filter())
        if pages:
            menu_attr_class = page_objects[0].menu_item.__class__  # hack.
            menu_attrs_objects = dict([(x.page_id, x) for x in menu_attr_class.objects.all()])
        else:
            menu_attrs_objects = {}

        for page in page_objects:
            pages.by_pk[page.pk] = page
            pages.by_path[page.path] = page
            pages.by_name[page.name] = page
            pages.by_level.setdefault(page.level, []).append(page)
            if page.parent_id:
                pages.by_parent.setdefault(page.parent_id, []).append(page)
            page.set_allpages_cache(pages)
            page.menu_item = menu_attrs_objects[page.pk]
        return pages

    def get_absolute_url(self):
        return self.path

    def get_native_page_name(self):
        if not self.path:
            return ''
        view, args, kwargs = resolve(self.path) #@UnusedVariable
        from pagemagic.views import handle_page
        if view == handle_page:
            return ''
        return '%s.%s' % (view.__module__, view.__name__)
    get_native_page_name.short_description = _('Handler')
    get_native_page_name.help_text = _('Handler')

    def is_native_page(self):
        return bool(self.get_native_page_name())

    def objects_filter(self):
        return self.__class__.objects.filter(parent=self.parent)

    def adm_menu_title(self):
        return mark_safe(u'%s |- %s' % ('&nbsp;' * self.level * 4, self.menu_item.title))
    adm_menu_title.short_description = _('Page')
    adm_menu_title.allow_tags = True

    def has_enabled_children(self):
        if hasattr(self, '_allpages_cache'):
            return bool(self._allpages_cache.by_parent.get(self.pk))
        else:
            return Page.objects.filter(parent=self, enabled=True).count() > 0

    def has_children(self):
        return bool(self.get_children())

    def has_in_parents(self, page):
        p = self
        while p.parent is not None:
            if p.parent == page:
                return True
            p = p.parent
        return False

    def get_children(self):
        if not hasattr(self, '_children'):
            if hasattr(self, '_allpages_cache'):
                self._children = self._allpages_cache.by_parent.get(self.pk, [])
            else:
                self._children = Page.objects.filter(parent=self).all().select_related()
        return self._children

    @classmethod
    def get_root_items(cls):
        return cls.objects.filter(parent=None)

    def _calculate_level(self):
        level = 0
        p = self
        while p.parent is not None:
            p = p.parent
            level += 1
        return level

    @classmethod
    def items_and_level(cls, parent=None):
        if parent:
            items = cls.objects.filter(parent=parent)
            level = parent.level + 1
        else:
            items = cls.objects.filter(level=0)
            level = 0
        return items, level

    def get_self_or_child_path(self):
        """Self path or first path from children"""
        if self.path:
            return self.path
        elif self.has_children():
            return self.get_children()[0].get_self_or_child_path()
        else:
            return ''

    def save(self, *args, **kwargs):
        self.path = self.path.strip()
        self.name = self.name.strip()
        self.level = self._calculate_level()
        super(Page, self).save(*args, **kwargs)

    def __eq__(self, other):
        return isinstance(other, self.__class__) and self.pk == other.pk

    class Meta:
        ordering = ('order',)
        #ordering = ('parent__id', 'order',)
        verbose_name = _('site page')
        verbose_name_plural = _('site pages')

    def is_splitter(self):
        return self.menu_item.title.startswith('-')

    def __unicode__(self):
        try:
            return self.menu_item.title
        except models.ObjectDoesNotExist:
            return 'new page'


class AbstractMenuItemAttrs(models.Model):
    page = models.OneToOneField(Page, related_name="menu_item")

    # must be redifined! TODO make checking
    #title = models.CharField(_('menu item title'), max_length=255)

    def __unicode__(self):
        return u'%s menu_item' % self.page

    class Meta:
        abstract = True
        verbose_name = _('menu item')
        verbose_name_plural = _('menu item')


class AbstractPageAttrs(models.Model):
    page = models.OneToOneField(Page, related_name='content')
    template = models.CharField(_('template'), max_length=255,
        blank=True, default='default.html')

    def save(self, *args, **kwargs):
        if not self.page.path:
            self.template = ''
        return super(AbstractPageAttrs, self).save(*args, **kwargs)

#    def get_template(self):
#        return self.template or 'pagemagic/default.html'
    def get_template(self):
        return self.template

    def __unicode__(self):
        return u'%s content' % self.page

    class Meta:
        abstract = True
        verbose_name = _('content')
        verbose_name_plural = _('content')

AbstractContentAttrs = AbstractPageAttrs
